package net.gdface.service.search;

import java.net.MalformedURLException;
import java.net.URI;

import net.gdface.httpclient.FailOpenPage;
import net.gdface.httpclient.SyncClientManager;
import net.gdface.service.client.FetchImage;
import net.gdface.service.client.WorkDataJSON;
import net.gdface.utils.Assert;
import net.gdface.utils.Judge;

import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author guyadong
 *
 */
public abstract class SearchImgImpl  extends SearchImgAbstractImpl implements Runnable {
	private static final Logger logger = LoggerFactory.getLogger(SearchImgImpl.class);
	private static final int OPEN_SE_WEB_INTERVAL_MILLS=10*1000;
	protected final String keyword;
	private final SearchSimilarImg simSearchProcessor;
	private final FetchImage imgProcessor;
	//////////////////动态数据/////////////
	private URI webPage;
	private URI location;
	protected JSONObject jsonResp=null;
	protected int startIndex=0;
	protected int totalImage = -1;
	//////////////////////////////////////
	public SearchImgImpl(String keyword, SearchSimilarImg simiProcessor, FetchImage imgProcessor) {
		Assert.notEmpty(keyword, "keyword");
		Assert.notNull(simiProcessor, "simiProcessor");
		Assert.notNull(imgProcessor, "imgProcessor");
		this.keyword=keyword;
		this.simSearchProcessor=simiProcessor;
		this.imgProcessor=imgProcessor;
	}
	/**
	 * 根据关键字生成搜索图片请求的url
	 * @param lastPage TODO
	 * @param startIndex
	 * @return
	 */
	abstract protected URI nextPage(URI lastPage, int startIndex);
	abstract protected String getArrayKey();
	abstract protected String getResNumKey();	
	abstract protected URI createHTMLUri();
	abstract protected int getPageSize();
	abstract protected boolean isLast();
	protected abstract boolean isValidResp();
	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Runnable#run()
	 */
	public void run() {	
		logger.info(String.format("关键字[%s] 线程启动 start...", keyword));
		try {
			this.webPage = createHTMLUri();
			String locationStr = null;
			try {
				locationStr = SyncClientManager.getInstance().getLocation(webPage, OPEN_SE_WEB_INTERVAL_MILLS);
			} catch (FailOpenPage fe) {
				logger.warn(String.format("CANT OPEN SE PAGE(搜索引擎页面打开失败) %s",fe.toString()));
			}
			if (Judge.isEmpty(locationStr)) {
				location = webPage;
			} else
				location = URI.create(locationStr);
			URI target = null;
			boolean retry=false;
			do{
				try {					
					target = nextPage(target, startIndex);
					jsonResp=null;
					getImgInfoFromSE(target, keyword);
					//正常返回则下标指向下一页
					//抛出FailOpenPage异常时会重试当前页一次
				}  catch (FailOpenPage e) {
					if(!retry){
						retry=true;
						continue;
					} else {
						logger.warn(String.format("%s:%s", e.getClass().getSimpleName(), e.getCause().toString()));
					}
				}
				startIndex += getPageSize();retry=false;
			}while(!(isLast()||isFinished.get()));
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		}
		logger.info(String.format("关键字[%s] 线程结束 stop...", keyword));
	}
	
	@Override
	public JSONArray getImgInfoFromSE(URI target, final String keyword) throws FailOpenPage, InterruptedException, IllegalArgumentException {
		Assert.notNull(target, "target");
		
		JSONArray imgArray = new JSONArray();
		try {
			jsonResp = getJSON(target, null, -1L,new BasicNameValuePair("Referer", location.toString()));
			if(!isValidResp())
				return imgArray;
			getTotalNumFromJsonResp();
			imgArray = getArrayFromJsonResp();
			for (int i = 0; i < imgArray.length()&&!isFinished.get(); i++) {
				try {
					JSONObject jo = imgArray.getJSONObject(i);
					jo.put(ImgJsonDecoder.KEY_KEYWORD, this.keyword);
					//设置解码器类型
					jo.put(ImgJsonDecoder.KEY_DECODER, ImgJsonDecoder.SO360.getClass().getName());
					ImgInfo imginfo = ImgJsonDecoder.SO360.create(jo);
					URI imgUri = imginfo.getLocaction();
					WorkDataJSON woc = new WorkDataJSON(jo);
					woc.setVariables(WorkDataJSON.VAR_IMGINFO, imginfo);
					//设置强制检测人脸标志，保证每次获取的样本图片都是有人脸的，
					//否则，搜索出来的相似图片有人脸的可能性就大大降低
					woc.setVariables(WorkDataJSON.VAR_CHECKFACE, true);
					String imgRef = this.imgProcessor.fetchSyncSleepIfNoTimeup(woc, true, false);
					if (!Judge.isEmpty(imgRef)) {
						simSearchProcessor.setMd5Ref(imgRef);
						simSearchProcessor.getImgInfoFromSE(imgUri, this.keyword);
					}
				} catch (FailOpenPage e) {
					logger.warn(String.format("[%s] %s",e.getClass().getSimpleName(),e.getCause().toString()));
				} catch (MalformedURLException e) {
					logger.info(String.format("图片链接错误 %s",e.getMessage()));
				}finally{
					
				}
			}
		} catch(JSONException e){
			logger.warn(e.getMessage(),e);
		}finally {}
		return imgArray;
	}
	protected final int getTotalNumFromJsonResp() throws JSONException {
		try {
			int total = jsonResp.getInt(getResNumKey());
			if(total>this.totalImage){
				this.totalImage=total;
			}
			return this.totalImage;
		} catch (JSONException e) {
			logger.error(String.format("CAN'T GET total count from JSON %s", e.toString()));
			throw e;
		}
	}
	protected final JSONArray getArrayFromJsonResp() throws JSONException {
		try {
			return jsonResp.getJSONArray(getArrayKey());
		} catch (JSONException e) {
			logger.error(String.format("CAN'T GET JSONArray from JSON %s", e.toString()));
			throw e;
		}
	}

	
}